package org.yutian.springboot.json;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

public class JacksonTool {
    // 默认能够识别HtmlEscaping转换的字符，并正确解码，且默认不会继续HtmlEscaping编码
    private final static ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.setLocale(Locale.getDefault());
        objectMapper.writerWithDefaultPrettyPrinter();
        //在序列化时忽略值为 null 的属性
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.findAndRegisterModules();
        //objectMapper.registerTrimModule(false)
        //objectMapper.registerDateModule(true);
        //objectMapper.registerEnumModule(true);
        // 对于日期类型为 java.time.LocalDate，还需要添加代码 mapper.registerModule(new JavaTimeModule())
        objectMapper.registerModule(new JavaTimeModule());
        // jackson默认是大小写敏感的。这里设置为不敏感！
        objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);
        objectMapper.configure(MapperFeature.IGNORE_DUPLICATE_MODULE_REGISTRATIONS, true);
        objectMapper.configure(MapperFeature.USE_GETTERS_AS_SETTERS, false);
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_YAML_COMMENTS, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        objectMapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, false);
        // 在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ TODO
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 设置toJson的Date字段格式，将只能解析该格式
        objectMapper.setDateFormat(smt);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
        objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        // //在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(com.fasterxml.jackson.core.JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
    }

    public static boolean isJsonArray(String dataJson){
        if(StringUtils.isBlank(dataJson)){
            return false;
        }
        return dataJson.startsWith("[") && dataJson.endsWith("]");
    }

    public static boolean isJson(String dataJson){
        if(StringUtils.isBlank(dataJson)){
            return false;
        }
        return dataJson.startsWith("{") && dataJson.endsWith("}");
    }

    public static<T> T fromJson(String dataJson, TypeReference<T> type){
        if(StringUtils.isBlank(dataJson)){
            return null;
        }
        try {
            return objectMapper.readValue(dataJson, type);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        // return gson.fromJson(dataJson, type);
    }

    public static<T> T fromJson(String dataJson, Class<T> z){
        if(StringUtils.isBlank(dataJson)){
            return null;
        }
        try {
            return objectMapper.readValue(dataJson, z);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static JsonNode fromJsonToJsonObject(String json) {
        if(StringUtils.isBlank(json)){
            return null;
        }
        //Json的解析类对象
        JsonNode node = null;
        try {
            node = objectMapper.readTree(json);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return node;
    }

    public static Integer getIntObject(String dataJson, String key) {
        if(StringUtils.isBlank(dataJson)){
            return null;
        }
        JsonNode jsonObject = fromJsonToJsonObject(dataJson);
        JsonNode element = jsonObject.get(key);
        if(null == element || element.isNull()){
            // key不存在或key值为null
            return null;
        }
        return element.asInt();
    }

    public static String getStringObject(String dataJson, String key) {
        if(StringUtils.isBlank(dataJson)){
            return null;
        }
        JsonNode jsonObject = fromJsonToJsonObject(dataJson);
        JsonNode element = jsonObject.get(key);
        if(null == element || element.isNull()){
            // key不存在或key值为null
            return null;
        }
        return element.asText();
    }

    /**
     * 注：Object无法转为String
     * @param dataJson
     * @return
     */
    @Deprecated
    public static Map<String, String> fromJsonToMapStr(String dataJson){
        TypeReference<HashMap<String, String>> type = new TypeReference<HashMap<String, String>>() {
        };
        Map<String, String> map = fromJson(dataJson, type);
        return map;
    }

    /**
     * 从json转到对象
     * 注：若json某个字段是Date类型，则无法使用gson.fromJson转换（Date转成了String）；若数值类型，会转为Double！
     * @param json
     * @return
     */
    public static Map<String, Object> fromJsonToMap(String json) {
        return fromJson(json, new TypeReference<Map<String, Object>>(){});
    }

    public static List<Map<String, Object>> fromJsonToListMapObj(String dataJson){
        TypeReference<List<Map<String, Object>>> type = new TypeReference<List<Map<String, Object>>>() {};
        List<Map<String, Object>> listObj = fromJson(dataJson, type);
        return listObj;
    }


    /**
     * 注：Object无法转为String
     * @param json
     * @return
     */
    @Deprecated
    public static List<Map<String, String>> fromJsonToListMapStr(String json){
        TypeReference<List<Map<String, String>>> type = new TypeReference<List<Map<String, String>>>() {};
        List<Map<String, String>> listObj = fromJson(json, type);
        return listObj;
    }


    public static List<Map<String, Object>> fromJsonArray(Object detail) {
        //Json的解析类对象
        List<Map<String, Object>> dataSet = new ArrayList<Map<String, Object>>();
        if (detail instanceof String) {
            TypeReference<List<Map<String, Object>>> type = new TypeReference<List<Map<String, Object>>>() {};
            dataSet = fromJson(detail.toString(), type);
        } else {
            List<Object> detailList = (List<Object>) detail;
            for (Object obj : detailList) {
                Map<String, Object> t = null;
                if (obj instanceof String) {
                    t = fromJsonToMap(obj.toString());
                } else if (obj instanceof Map){
                    t = (Map<String, Object>) obj;
                } else {
                    t = fromJsonToMap(toJson(obj));
                }
                dataSet.add(t);
            }
        }
        return dataSet;
    }


    /**
     * java.lang.reflect.Type type = new TypeToken<List<User>>() {}.getType();
     * List<User> res = GsonTool.fromJson(json, type);
     * @param json
     * @param tp
     * @param <T>
     * @return
     */
    @Deprecated
    public static <T> List<T> fromJsonArray(String json, TypeReference<T> tp) {
        if(StringUtils.isBlank(json)){
            return null;
        }
        try {
            //Json的解析类对象
            JsonNode node = objectMapper.readTree(json);

            List<T> beanList = new ArrayList<>();

            //加强for循环遍历JsonArray
            for (JsonNode item : node) {
                //使用GSON，直接转成Bean对象
                T bean = objectMapper.readValue(item.toString(), tp);
                beanList.add(bean);
            }
            return beanList;
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }


    public static String toJson(Object data) {
        if(null == data){
            return null;
        }
        try {
            return objectMapper.writeValueAsString(data);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] serialize(Object data) {
        if(null == data){
            return null;
        }
        try {
            return objectMapper.writeValueAsBytes(data);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String toJsonPretty(Object data) {
        if(null == data){
            return null;
        }
        try {
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}
